home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / tde3.zip / CONSOLE.C < prev    next >
C/C++ Source or Header  |  1993-06-05  |  53KB  |  1,553 lines

  1. /*
  2.  * All video and keyboard functions were gathered into one file.
  3.  *
  4.  * This file contains the keyboard and video i/o stuff.  Most of this stuff
  5.  * is specific to the PC hardware, but it should be easily modified when
  6.  * porting to other platforms.  With a few key functions written in
  7.  * assembly, we have fairly fast video performance and good keyboard control.
  8.  * Incidentally, the commented C code in the functions perform the same
  9.  * function as the assembly code.  In earlier versions of TDE, I didn't
  10.  * update the commented C code when I changed the assembly code.  The
  11.  * C and assembly should be equivalent in version 2.2.
  12.  *
  13.  * Although using a curses type package would be more portable, curses
  14.  * can be slow on PCs.  Let's keep our video and keyboard routines in
  15.  * assembly.  I feel the need for speed.
  16.  *
  17.  * Being that TDE 2.2 keeps an accurate count of characters in each line, we
  18.  * can allow the user to enter any ASCII or Extended ASCII key.
  19.  *
  20.  * Determining the video adapter type on the PC requires a function.  In
  21.  *  TDE, that function is:
  22.  *
  23.  *                void video_config( struct vcfg *cfg )
  24.  *
  25.  * video_config( ) is based on Appendix C in _Programmer's Guide to
  26.  *  PC & PS/2 Video Systems_ by Richard Wilton.
  27.  *
  28.  * See:
  29.  *
  30.  *   Richard Wilton, _Programmer's Guide to PC & PS/2 Video Systems_,
  31.  *    Microsoft Press, Redmond, Washington, 1987, Appendix C, pp 511-521.
  32.  *    ISBN 1-55615-103-9.
  33.  *
  34.  *
  35.  * New editor name:  TDE, the Thomson-Davis Editor.
  36.  * Author:           Frank Davis
  37.  * Date:             June 5, 1991, version 1.0
  38.  * Date:             July 29, 1991, version 1.1
  39.  * Date:             October 5, 1991, version 1.2
  40.  * Date:             January 20, 1992, version 1.3
  41.  * Date:             February 17, 1992, version 1.4
  42.  * Date:             April 1, 1992, version 1.5
  43.  * Date:             June 5, 1992, version 2.0
  44.  * Date:             October 31, 1992, version 2.1
  45.  * Date:             April 1, 1993, version 2.2
  46.  * Date:             June 5, 1993, version 3.0
  47.  *
  48.  * This code is released into the public domain, Frank Davis.
  49.  * You may distribute it freely.
  50.  */
  51.  
  52.  
  53. #include "tdestr.h"
  54. #include "common.h"
  55. #include "define.h"
  56. #include "tdefunc.h"
  57.  
  58. #include <bios.h>               /* for direct BIOS keyboard input */
  59.  
  60.  
  61. /*******************************************************/
  62. /*                                                     */
  63. /*  1) initialize the video and keyboard structures    */
  64. /*                                                     */
  65. /*******************************************************/
  66.  
  67.  
  68. /*
  69.  *   BIOS Data Areas
  70.  *
  71.  *   See:
  72.  *
  73.  *      IBM Corp., _Technical Reference:  Personal Computer AT_,
  74.  *      Boca Raton, Florida, 1984, IBM part no. 1502494,
  75.  *      pp 5-29 thru 5-32.
  76.  *
  77.  *  These addresses, variable names, types, and descriptions are directly
  78.  *   from the IBM AT Technical Reference manual, BIOS listing, copyright IBM.
  79.  *
  80.  *   Address  Name           Type   Description
  81.  *   0x0449   CRT_MODE       Byte   Current CRT mode
  82.  *   0x044a   CRT_COLS       Word   Number columns on screen
  83.  *   0x044c   CRT_LEN        Word   length of regen buffer, video buffer, bytes
  84.  *   0x044e   CRT_START      Word   Starting address of regen buffer
  85.  *   0x0450   CURSOR_POSN    Word   cursor for each of up to 8 pages.
  86.  *   0x0460   CURSOR_MODE    Word   current cursor mode setting.
  87.  *   0x0462   ACTIVE_PAGE    Byte   Current page
  88.  *   0x0463   ADDR_6845      Word   base address for active display card
  89.  *   0x0465   CRT_MODE_SET   Byte   current mode of display card
  90.  *   0x0466   CRT_PALETTE    Byte   overscan color for CGA, EGA, and VGA.
  91.  *   0x0467   io_rom_init    Word   Pointer to optional i/o rom init routine
  92.  *   0x0469   io_rom_seg     Word   Pointer to io rom segment
  93.  *   0x046b   intr_flag      Byte   Flag to indicate an interrupt happened
  94.  *   0x046c   timer_low      Word   Low word of timer count
  95.  *   0x046e   timer_high     Word   High word of timer count
  96.  *   0x0470   timer_ofl      Byte   Timer has rolled over since last count
  97.  *   0x0471   bios_break     Byte   Bit 7 = 1 if Break Key has been hit
  98.  *   0x0472   reset_flag     Word   Word = 1234h if keyboard reset underway
  99.  *   0x0484   ROWS           Byte   Number of displayed character rows - 1
  100.  *   0x0485   POINTS         Word   Height of character matrix
  101.  *   0x0487   INFO           Byte   EGA and VGA display data
  102.  *   0x0488   INFO_3         Byte   Configuration switches for EGA and VGA
  103.  *   0x0489   flags          Byte   Miscellaneous flags
  104.  *   0x0496   kb_flag_3      Byte   Additional keyboard flag
  105.  *   0x048A   DCC            Byte   Display Combination Code
  106.  *   0x04A8   SAVE_PTR       Dword  Pointer to BIOS save area
  107.  */
  108. void video_config( struct vcfg *cfg )
  109. {
  110. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  111.  
  112. struct LOWMEMVID
  113. {
  114.    char     vidmode;           /* 0x449 */
  115.    unsigned scrwid;            /* 0x44A */
  116.    unsigned scrlen;            /* 0x44C */
  117.    unsigned scroff;            /* 0x44E */
  118.    struct   LOCATE
  119.    {
  120.       unsigned char col;
  121.       unsigned char row;
  122.    } csrpos[8];                /* 0x450 */
  123.    struct   CURSIZE
  124.    {
  125.       unsigned char end;
  126.       unsigned char start;
  127.    } csrsize;                  /* 0x460 */
  128.    char      page;             /* 0x462 */
  129.    unsigned  addr_6845;        /* 0x463 */
  130.    char      crt_mode_set;     /* 0x465 */
  131.    char      crt_palette;      /* 0x466 */
  132.    char      system_stuff[29]; /* 0x467 */
  133.    char      rows;             /* 0x484 */
  134.    unsigned  points;           /* 0x485 */
  135.    char      ega_info;         /* 0x487 */
  136.    char      info_3;           /* 0x488 */
  137.    char      skip[13];         /* 0x489 */
  138.    char      kb_flag_3;        /* 0x496 */
  139. } vid;
  140. struct LOWMEMVID _far *pvid = &vid;
  141. #pragma pack( )    /* revert to previously defined pack pragma. */
  142.  
  143. union REGS in, out;
  144. unsigned char temp, active_display;
  145.  
  146.    /*
  147.     * Move system information into our video structure.
  148.     */
  149.    _fmemmove( pvid, (void far *)0x00000449l, sizeof( vid ) );
  150.  
  151.    cfg->rescan = FALSE;
  152.    in.x.ax =  0x1a00;
  153.    int86( VIDEO_INT, &in, &out );
  154.    temp = out.h.al;
  155.    active_display = out.h.bl;
  156.    if (temp == 0x1a && (active_display == 7 || active_display == 8))
  157.       g_display.adapter = VGA;
  158.    else {
  159.       in.h.ah =  0x12;
  160.       in.h.bl =  0x10;
  161.       int86( VIDEO_INT, &in, &out );
  162.       if (out.h.bl != 0x10) {         /* EGA */
  163.          if (vid.ega_info & 0x08)
  164.             g_display.adapter = vid.addr_6845 == 0x3d4 ? CGA : MDA;
  165.          else
  166.             g_display.adapter = EGA;
  167.       } else if (vid.addr_6845 == 0x3d4)
  168.          g_display.adapter = CGA;
  169.       else
  170.          g_display.adapter = MDA;
  171.    }
  172.  
  173.    if (g_display.adapter == CGA || g_display.adapter == EGA) {
  174.       if (g_display.adapter == CGA)
  175.          cfg->rescan = TRUE;
  176.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0607 : 0x0407;
  177.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x0407 : 0x0607;
  178.    } else {
  179.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0b0c : 0x070b;
  180.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x070b : 0x0b0c;
  181.    }
  182.  
  183.    cfg->mode = vid.vidmode;
  184.    if (vid.addr_6845 == 0x3D4) {
  185.       cfg->color = TRUE;
  186.       cfg->videomem = (void far *)0xb8000000l;
  187.    } else {
  188.       cfg->color = FALSE;
  189.       cfg->videomem = (void far *)0xb0000000l;
  190.    }
  191.  
  192.    /*
  193.     * let save the overscan color
  194.     */
  195.    g_display.old_overscan = vid.crt_palette;
  196.  
  197.  
  198.    /*
  199.     * Get keyboard type.  Since there is no interrupt that determines
  200.     * keyboard type, use this method.  Look at bit 4 in keyboard flag3.
  201.     * This method is not always foolproof on clones.
  202.     */
  203.    if ((vid.kb_flag_3 & 0x10) != 0)
  204.       mode.enh_kbd = TRUE;
  205.    else
  206.       mode.enh_kbd = FALSE;
  207.    if (mode.enh_kbd == FALSE)
  208.       simulate_enh_kbd( 1 );
  209. }
  210.  
  211.  
  212. /*********************************************/
  213. /*                                           */
  214. /*  2) keyboard i/o routines, PC specific    */
  215. /*                                           */
  216. /*********************************************/
  217.  
  218.  
  219. /*
  220.  * The next function was written by Tom Waters, twaters@relay.nswc.navy.mil, and
  221.  * modified extensively by Frank Davis.
  222.  *
  223.  * "I use ANSI.SYS to redefine a few of my function keys and this causes a
  224.  * problem when getch() is used in a program.  For example, instead of returning
  225.  * 321 for the F7, I get the redefined string inserted in the text. So, instead
  226.  * of using getch(), I use the following function ..."
  227.  *
  228.  * Tom, thanks for the info and solution.  I'm sure your function will be
  229.  * be appreciated by everyone with ANSI key defs, Frank.
  230.  */
  231.  
  232. /*
  233.  * Name:    getkey
  234.  * Purpose: use bios to get keyboard input (getch has trouble w/ ANSI
  235.  *          redefined keys)
  236.  * Date:    July 2, 1991
  237.  * Modified:July 12, 1991, Frank Davis - accept ALT-xxx keyboard entry
  238.  *          September 10, 1991, Frank Davis - add support for Ctrl+Up, etc...
  239.  * Passed:  None
  240.  * Notes:   Uses the BIOS to read the next keyboard character.  Service 0x00
  241.  *           is the XT keyboard read.  Service 0x10 is the extended keyboard
  242.  *           read.  Test for a bunch of special cases.  Allow the user to enter
  243.  *           any ASCII or Extended ASCII code as a normal text characters.
  244.  *
  245.  *          Control @ is defined as 0.  we need to do a special test
  246.  *           for this key, otherwise it's interpretted as an Alt key.  It's
  247.  *           the only "regular" Control key that returns 0 in AL and the scan
  248.  *           byte in AH.  The "regular" Control keys are those in the range
  249.  *           0-31 and they return the Control character in AL and the scan
  250.  *           code in AH.  All of the Alt + keys return 0 in AL and
  251.  *           the scan code in ah.
  252.  *
  253.  *          This function was written for US keyboards.  It may have to be
  254.  *           modified for other keyboards, eg. Belgium, Canada, Czech,
  255.  *           Slovak, Denmark, France, Germany, etc...
  256.  *
  257.  *          if Ctrl-Break is pressed, it returns 0xffff as the key pressed.
  258.  *           let's set it to CONTROL_BREAK == 269 and do nothing.
  259.  */
  260. int getkey( void )
  261. {
  262. unsigned key, num_lock, control, shift;
  263. register scan;
  264. register unsigned lo;
  265.  
  266. /*
  267.  * this code is used during testing to check the amount of memory
  268.  *    in the near heap.
  269.  *
  270.  * char buff[MAX_COLS];
  271.  * ultoa( _memavl( ), buff, 10 );
  272.  * s_output( "h=       ", g_display.mode_line, 37, g_display.mode_color );
  273.  * s_output( buff, g_display.mode_line, 39, g_display.mode_color );
  274.  */
  275.  
  276.    /*
  277.     * lets spin on waitkey until the user presses a key.  waitkey polls
  278.     *  the keyboard and returns 0 when a key is waiting.
  279.     */
  280.    while (waitkey( mode.enh_kbd ));
  281.  
  282.    /*
  283.     *  _bios_keybrd == int 16.  It returns the scan code in ah, hi part of key,
  284.     *   and the ascii key code in al, lo part of key.  If the character was
  285.     *   entered via ALT-xxx, the scan code, hi part of key, is 0.
  286.     */
  287.    if (mode.enh_kbd) {
  288.       key = _bios_keybrd( 0x10 );
  289.       lo  = _bios_keybrd( 0x12 );
  290.  
  291.       /*
  292.        * couple of special cases:
  293.        *   on the numeric keypad, some keys return 0xe0 in the lo byte.
  294.        *   1) if user enters Alt-224, then the hi byte == 0 and lo byte == 0xe0.
  295.        *   we need to let this get thru as an Extended ASCII char.  2) although
  296.        *   we could make the cursor pad keys do different functions than the
  297.        *   numeric pad cursor keys, let's set the 0xe0 in the lo byte to zero
  298.        *   and forget about support for those keys.
  299.        */
  300.       if ((key & 0x00ff) == 0x00e0 && (key & 0xff00) != 0)
  301.          key = key & 0xff00;
  302.    } else {
  303.       key = _bios_keybrd( 0 );
  304.       lo  = _bios_keybrd( 2 );
  305.    }
  306.    num_lock = lo & 0x20;
  307.    control  = lo & 0x04;
  308.    shift    = lo & 0x03;
  309.    scan = (key & 0xff00) >> 8;
  310.    lo = key & 0X00FF;
  311.  
  312.    if (lo == 0) {
  313.       /*
  314.        * special case for Control @, which is defined as 0 or NULL.
  315.        */
  316.       if (scan == 3)
  317.          lo = 430;
  318.  
  319.       /*
  320.        * when first byte is 0, map it above 256, so that we can
  321.        *  let ALT-xxx keys map to their 'natural' place.  In
  322.        *  otherwords, use 0-255 as normal text characters and
  323.        *  those >= 256 are function keys.
  324.        */
  325.       else
  326.          lo = scan | 0x100;
  327.  
  328.    /*
  329.     * now test for Control-Break.  let's set this to do nothing in the
  330.     *  editor.  manually map Control-Break to 269 - DO NOT assign
  331.     *  any function to 269.
  332.     */
  333.    } else if (key == 0xffff)
  334.       lo = CONTROL_BREAK;
  335.  
  336.  
  337.    /*
  338.     * Pressing Control+BackSpace generates the 0x7f character.  Instead of
  339.     * 0x7f, make lo the ASCII backspace character.  If anyone wants the
  340.     * 0x7f character, then they can enter it via ALT+xxx.
  341.     */
  342.    if (scan == 14 && lo == 0x7f)
  343.       lo = 8;
  344.  
  345.    /*
  346.     * At the bottom of page 195 in MASM 6.0 ref manual, "..when the keypad
  347.     *  ENTER and / keys are read through the BIOS interrupt 16h, only E0h
  348.     *  is seen since the interrupt only gives one-byte scan codes."
  349.     */
  350.    else if (scan == 0xe0) {
  351.       /*
  352.        * plain Grey Enter
  353.        */
  354.       if (lo == 13 && !shift)
  355.          lo = 285;
  356.       /*
  357.        * shift Grey Enter
  358.        */
  359.       else if (lo == 13)
  360.          lo = 298;
  361.       /*
  362.        * control Grey Enter
  363.        */
  364.       else if (lo == 10)
  365.          lo = 299;
  366.    }
  367.  
  368.    /*
  369.     *  let's massage all of the control key combinations.
  370.     */
  371.    if (lo < 32) {
  372.  
  373.       /*
  374.        * My machine at home is sorta weird.  On every machine that I've
  375.        *  tested at the awffice, the ALT-xxx combination returns 0 for the
  376.        *  scan byte and xxx for the ASCII code.  My machine returns 184 (decimal)
  377.        *  as the scan code?!?!?  I added the next two lines for my machine at
  378.        *  home.  I wonder if someone forgot to zero out ah for Alt keypad entry
  379.        *  when they wrote my bios?
  380.        */
  381.       if (scan > 0x80)
  382.          scan = 0;
  383.  
  384.       /*
  385.        * Separate the ESC key from the ^[ key.  The scan code for the ESC
  386.        *  key is 1.  Map this to a different index into the key function
  387.        *  array just in case someone wants to define ESC or ^[ to different
  388.        *  functions.  BTW, ESC and ^[ return the same ASCII code, 27.
  389.        */
  390.       else if (scan == 1) {
  391.          if (shift)
  392.             lo = 259;
  393.          else if (control)
  394.             lo = 260;
  395.          else
  396.             lo = 258;
  397.       }
  398.  
  399.       /*
  400.        * Scan code for Enter = 28.  Separate the various Enter keys.
  401.        */
  402.       else if (scan == 28) {
  403.          if (shift)
  404.             lo = 263;
  405.          else if (control)
  406.             lo = 264;
  407.          else
  408.             lo = 262;
  409.       }
  410.  
  411.       /*
  412.        * Scan code for Backspace = 14.  Separate the various BackSpace keys.
  413.        */
  414.       else if (scan == 14) {
  415.          if (shift)
  416.             lo = 266;
  417.          else if (control)
  418.             lo = 267;
  419.          else
  420.             lo = 265;
  421.       }
  422.  
  423.       /*
  424.        * Scan code for Tab = 15.  Separate the tab key.
  425.        */
  426.       else if (scan == 15) {
  427.          lo = 268;
  428.       }
  429.  
  430.       /*
  431.        * if scan code is not 0, then a Control key was pressed.  Map
  432.        *  those keys to the WordStar commands.
  433.        */
  434.       else if (scan > 0)
  435.          lo += 430;
  436.  
  437.    } else if (!num_lock) {
  438.       switch (scan) {
  439.          /*
  440.           * scan code for grey - == 74.  if num_lock is not toggled, assign it
  441.           *  to the scroll line up function.
  442.           */
  443.          case 74 :
  444.             lo = 423;
  445.             break;
  446.  
  447.          /*
  448.           * scan code for grey + == 78.  if num_lock is not toggled, assign it
  449.           *  to the scroll line down function.  if shift grey + then stationary
  450.           *  scroll down.
  451.           */
  452.          case 78 :
  453.             lo = 424;
  454.             break;
  455.       }
  456.    }
  457.  
  458.  
  459.    /*
  460.     * let's set up for the Shift+Alt and Control+Alt keys.
  461.     *  With these key combinations, we can do the International keyboard
  462.     *  stuff, see the Microsoft MS DOS 5.0 manual pages 623-637.
  463.     */
  464.    if (lo > 256 && (shift || control)) {
  465.  
  466.       /*
  467.        * add 55 to Ctrl+Left thru Ctrl+Home when the shift key is pressed.
  468.        *  this is not part of the International keyboard stuff, just a way
  469.        *  to assign the horizontal scroll left and right funcs to cursor keys.
  470.        */
  471.       if (shift) {
  472.          if (lo >= 371 && lo <= 374)
  473.             lo += 55;
  474.  
  475.          /*
  476.           * if shift is down, map alt 1! thru alt =+ to shift alt 1! thru alt =+
  477.           */
  478.          else if (lo >= 376 && lo <= 387)
  479.             lo += 86;
  480.  
  481.          /*
  482.           * internation keyboard stuff
  483.           */
  484.          else if (lo >= 272 && lo <= 309)
  485.             lo += 202;
  486.       }
  487.    }
  488.  
  489.    /*
  490.     * map the enter key to line feed.
  491.     */
  492.    if (lo == 10  &&  scan != 0)
  493.       lo = 425;
  494.    return( lo );
  495. }
  496.  
  497.  
  498. /*
  499.  * Name:    waitkey
  500.  * Purpose: call the BIOS keyboard status subfunction
  501.  * Date:    October 31, 1992
  502.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  503.  * Returns: 1 if no key ready, 0 if key is waiting
  504.  * Notes:   lets get the keyboard status so we can spin on this function until
  505.  *           the user presses a key.  some OS replacements for DOS want
  506.  *           application programs to poll the keyboard instead of rudely
  507.  *           sitting on the BIOS read key function.
  508.  */
  509. int  waitkey( int enh_keyboard )
  510. {
  511.    return( _bios_keybrd( enh_keyboard ? 0x11 : 0x01 ) == 0 ? 1 : 0 );
  512. }
  513.  
  514.  
  515. /*
  516.  * Name:    getfunc
  517.  * Purpose: get the function assigned to key c
  518.  * Date:    July 11, 1991
  519.  * Passed:  c:  key just pressed
  520.  * Notes:   key codes less than 256 or 0x100 are not assigned a function.
  521.  *           The codes in the range 0-255 are ASCII and extended ASCII chars.
  522.  */
  523. int getfunc( int c )
  524. {
  525. register int i = c;
  526. int  key_found;
  527.  
  528.    if (!g_status.key_pending) {
  529.       i = c;
  530.       if (i <= 256)
  531.          i = 0;
  532.       else
  533.          i = key_func.key[i-256];
  534.    } else {
  535.  
  536.       /*
  537.        * allow the user to enter two-key combinations
  538.        */
  539.       key_found = FALSE;
  540.       for (i=0; i < MAX_TWO_KEYS; i++) {
  541.          if (g_status.first_key == two_key_list.key[i].parent_key &&
  542.                                c == two_key_list.key[i].child_key) {
  543.             i = two_key_list.key[i].func;
  544.             key_found = TRUE;
  545.             break;
  546.          }
  547.       }
  548.       if (key_found == FALSE)
  549.          i = ERROR;
  550.    }
  551.    return( i );
  552. }
  553.  
  554.  
  555. /*
  556.  * Name:    two_key
  557.  * Purpose: set the two_key flag and prompt for the next key.
  558.  * Date:    April 1, 1992
  559.  * Notes:   this function accepts two key commands.
  560.  */
  561. int  two_key( WINDOW *arg_filler )
  562. {
  563.    s_output( "Next Key..", g_display.mode_line, 67, g_display.diag_color );
  564.    g_status.key_pending = TRUE;
  565.    g_status.first_key = g_status.key_pressed;
  566.    return( OK );
  567. }
  568.  
  569.  
  570. /*
  571.  * Name:    flush_keyboard
  572.  * Purpose: flush keys from the keyboard buffer
  573.  * Date:    June 5, 1993
  574.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  575.  * Returns: 1 if no key ready, 0 if key is waiting
  576.  * Notes:   lets get the keyboard status so we can spin on this function until
  577.  *           the user presses a key.  some OS replacements for DOS want
  578.  *           application programs to poll the keyboard instead of rudely
  579.  *           sitting on the BIOS read key function.
  580.  */
  581. void flush_keyboard( void )
  582. {
  583.    if (mode.enh_kbd) {
  584.       while (!waitkey( mode.enh_kbd ))
  585.          _bios_keybrd( 0x10 );
  586.    } else {
  587.       while (!waitkey( mode.enh_kbd ))
  588.          _bios_keybrd( 0 );
  589.    }
  590. }
  591.  
  592.  
  593. /*********************************************/
  594. /*                                           */
  595. /*  3) video output routines, PC specific    */
  596. /*                                           */
  597. /*********************************************/
  598.  
  599.  
  600. /*
  601.  * Name:    xygoto
  602.  * Purpose: To move the cursor to the required column and line.
  603.  * Date:    September 28, 1991
  604.  * Passed:  col:    desired column (0 up to max)
  605.  *          line:   desired line (0 up to max)
  606.  * Notes;   use standard BIOS video interrupt 0x10 to set the set.
  607.  */
  608. void xygoto( int col, int line )
  609. {
  610. union REGS inregs, outregs;
  611.  
  612.    inregs.h.ah = 2;
  613.    inregs.h.bh = 0;
  614.    inregs.h.dh = (unsigned char)line;
  615.    inregs.h.dl = (unsigned char)col;
  616.    int86( 0x10, &inregs, &outregs );
  617. }
  618.  
  619.  
  620. /*
  621.  * Name:    update_line
  622.  * Purpose: Display the current line in window
  623.  * Date:    June 5, 1991
  624.  * Passed:  window:  pointer to current window
  625.  * Notes:   Show string starting at column zero and if needed blank rest
  626.  *           of line.  Put max_col in cx and count down.  When we run into
  627.  *           len, cx contains number of columns to blank out.  Use the
  628.  *           fast 'rep stosw' to clear the end of line.
  629.  *          The C routine was probably fast enough, but let's do some
  630.  *           assembly because it's so fun.
  631.  *          To handle line lengths longer than 255 characters,
  632.  *           block begin and end columns were changed from real
  633.  *           to virtual columns in this display routine.
  634.  */
  635. void update_line( WINDOW *window )
  636. {
  637. text_ptr text;      /* current character of orig begin considered */
  638. char far *screen_ptr;
  639. int  off;
  640. int  attr;
  641. int  line;
  642. int  col;
  643. int  bcol;
  644. int  bc;
  645. int  ec;
  646. int  normal;
  647. int  block;
  648. int  max_col;
  649. int  block_line;
  650. int  len;
  651. int  show_eol;
  652. int  c;
  653. long rline;
  654. file_infos *file;
  655.  
  656.    if (window->rline > window->file_info->length || window->ll->len == EOF
  657.              || !g_status.screen_display)
  658.       return;
  659.    file = window->file_info;
  660.    max_col = window->end_col + 1 - window->start_col;
  661.    line = window->cline;
  662.    normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color;
  663.    block = g_display.block_color;
  664.    show_eol = mode.show_eol;
  665.  
  666.    /*
  667.     * set the screen pointer to physical screen memory.
  668.     *       160 = 80 chars + 80 attr  for each line
  669.     */
  670.    screen_ptr = g_display.display_address;
  671.    off = line * 160 + window->start_col * 2;
  672.  
  673.    /*
  674.     * figure which line to display.
  675.     * actually, we could be displaying any line in any file.  we display
  676.     *  the line_buffer only if window->ll == g_status.buff_node
  677.     *  and window->ll-line has been copied to g_status.line_buff.
  678.     */
  679.    text = window->ll->line;
  680.    len  = window->ll->len;
  681.    if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) {
  682.       text = (text_ptr)g_status.line_buff;
  683.       len  = g_status.line_buff_len;
  684.    }
  685.    if (mode.inflate_tabs)
  686.       text = tabout( text, &len );
  687.  
  688.    /*
  689.     * lets look at the base column.  if the line to display is shorter
  690.     *  than the base column, then set text to eol and we can't see the
  691.     *  eol either.
  692.     */
  693.    bc = window->bcol;
  694.    if (bc > 0) {
  695.       if (text == NULL) {
  696.          show_eol = FALSE;
  697.          len = 0;
  698.       } else {
  699.          if ((col = len) < bc) {
  700.             bc = col;
  701.             show_eol = FALSE;
  702.          }
  703.          text += bc;
  704.          len  -= bc;
  705.       }
  706.    }
  707.  
  708.    /*
  709.     * for display purposes, set the line length to screen width if line
  710.     *  is longer than screen.  our assembly routine uses bytes and the
  711.     *  the line length can be longer than a byte.
  712.     */
  713.    if (len > max_col)
  714.       len = max_col;
  715.  
  716.    bcol = window->bcol;
  717.    rline = window->rline;
  718.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  719.       block_line = TRUE;
  720.    else
  721.       block_line = FALSE;
  722.  
  723.    /*
  724.     * do this if 1) a box block is marked, or 2) a stream block begins
  725.     *  and ends on the same line.
  726.     */
  727.    if (block_line == TRUE && (file->block_type == BOX ||
  728.          (file->block_type == STREAM &&
  729.          rline == file->block_br && rline == file->block_er))) {
  730.  
  731.       /*
  732.        * start with the bc and ec equal to physical block marker.
  733.        */
  734.       bc = file->block_bc;
  735.       ec = file->block_ec;
  736.       if (ec < bcol || bc >= bcol + max_col)
  737.          /*
  738.           * we can't see block if ending column is less than the base col or
  739.           *  the beginning column is greater than max_col.
  740.           */
  741.          ec = bc = max_col + 1;
  742.       else if (ec < bcol + max_col) {
  743.          /*
  744.           * if the ec is less than the max column, make ec relative to
  745.           *  base column then figure the bc.
  746.           */
  747.          ec = ec - bcol;
  748.          if (bc < bcol)
  749.             bc = 0;
  750.          else
  751.             bc = bc - bcol;
  752.       } else if (bc < bcol + max_col) {
  753.          /*
  754.           * if the bc is less than the max column, make bc relative to
  755.           *  base column then figure the ec.
  756.           */
  757.          bc = bc - bcol;
  758.          if (ec > bcol + max_col)
  759.             ec = max_col;
  760.          else
  761.             ec = ec - bcol;
  762.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  763.          /*
  764.           * if the block is wider than the screen, make bc start at the
  765.           *  logical begin and make ec end at the logical end of the
  766.           *  window.
  767.           */
  768.          bc = 0;
  769.          ec = max_col;
  770.       }
  771.  
  772.  
  773.    ASSEMBLE {
  774.         /*
  775.         ; Register strategy:
  776.         ;   bl == beginning column
  777.         ;   bh == ending column
  778.         ;   dl == normal text attribute
  779.         ;   dh == block attribute
  780.         ;   cl == current virtual column
  781.         ;   ch == maximum columns in window
  782.         ;   ES:DI == screen pointer (destination)
  783.         ;   DS:SI == text pointer (source)
  784.         ;   [bp+show_eol]  == access for local C variable
  785.         */
  786.  
  787.  
  788.         push    ds                      /* MUST save ds - push it on stack */
  789.         push    si                      /* save si on stack */
  790.         push    di                      /* save di on stack */
  791.  
  792. /*
  793. ;
  794. ; set up local register variables
  795. ;
  796. */
  797.         mov     ax, WORD PTR bc         /* get beginning column */
  798.         mov     bl, al                  /* keep it in bl */
  799.         mov     ax, WORD PTR ec         /* get ending column */
  800.         mov     bh, al                  /* keep it in bh */
  801.         mov     ax, WORD PTR normal     /* get normal attribute */
  802.         mov     dl, al                  /* keep it in dl */
  803.         mov     ax, WORD PTR block      /* get block attribute */
  804.         mov     dh, al                  /* keep it in dh */
  805.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  806.         mov     ch, al                  /* keep it in ch */
  807.         xor     cl, cl                  /* col = 0, keep col in cl */
  808. /*
  809. ;
  810. ; load screen and text pointer
  811. ;
  812. */
  813.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  814.         add     di, WORD PTR off                /* add offset of line */
  815.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  816.         mov     es, ax
  817.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  818.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  819.         mov     ds, ax                  /* move segment of text in ds */
  820.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  821.         jne     not_null                /* no, output string */
  822.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  823.         je      dspl_eol                /* yes, clear end of line */
  824.    }
  825. not_null:
  826.  
  827.    ASSEMBLE {
  828.         cmp     cl, ch                  /* is col == max_col? */
  829.         jge     getout                  /* yes, thru with line */
  830.         cmp     cl, BYTE PTR len        /* is col == len? */
  831.         je      dspl_eol                /* yes, must check block past eol */
  832.    }
  833. top:
  834.  
  835.    ASSEMBLE {
  836.         lodsb                   /* get next char in string */
  837.         mov     ah, dl          /* assume normal attribute */
  838.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  839.         jl      ch_out1         /* yes, show char and normal attribute */
  840.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  841.         jg      ch_out1         /* yes, show char and normal attribute */
  842.         mov     ah, dh          /* must be in a block - block attribute */
  843.    }
  844. ch_out1:
  845.  
  846.    ASSEMBLE {
  847.         stosw                   /* now show char on screen w/ attribute */
  848.         inc     cl              /* ++col */
  849.         cmp     cl, ch          /* is col == max_col? */
  850.         jge     getout          /* yes, thru with line */
  851.         cmp     cl, BYTE PTR len        /* is col == len? */
  852.         jl      top             /* yes, must check block past eol */
  853.    }
  854. dspl_eol:
  855.  
  856.    ASSEMBLE {
  857.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  858.         je      block_eol       /* show_eol flag is FALSE, blank line */
  859.         mov     al, EOL_CHAR    /* load some eol indicator */
  860.         mov     ah, dl          /* assume normal attribute */
  861.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  862.         jl      ch_out2         /* yes, show char and normal attribute */
  863.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  864.         jg      ch_out2         /* yes, show char and normal attribute */
  865.         mov     ah, dh          /* must be in a block - show block attribute */
  866.    }
  867. ch_out2:
  868.  
  869.    ASSEMBLE {
  870.         stosw                   /* write eol and attribute to screen */
  871.         inc     cl              /* ++col */
  872.         cmp     cl, ch          /* is col == max_col? */
  873.         je      getout          /* yes, we're done */
  874.    }
  875. block_eol:
  876.  
  877.    ASSEMBLE {
  878.         mov     al, ' '         /* clear rest of line w/ spaces */
  879.    }
  880. b1:
  881.  
  882.    ASSEMBLE {
  883.         mov     ah, dl          /* assume normal attribute */
  884.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  885.         jl      ch_out3         /* yes, show char and normal attribute */
  886.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  887.         jg      ch_out3         /* yes, show char and normal attribute */
  888.         mov     ah, dh          /* must be in a block - show block attribute */
  889.    }
  890. ch_out3:
  891.  
  892.    ASSEMBLE {
  893.         stosw                   /* write blank and attribute to screen */
  894.         inc     cl              /* ++col */
  895.         cmp     cl, ch          /* is col == max_col? */
  896.         jl      b1              /* while less output block */
  897.    }
  898. getout:
  899.  
  900.    ASSEMBLE {
  901.         pop     di
  902.         pop     si
  903.         pop     ds
  904.       }
  905.  
  906. /*
  907.       screen_ptr += off;
  908.       bcol = window->start_col;
  909.       for (col=0; col < max_col; col++, bcol++) {
  910.          attr = normal;
  911.          if (col >= bc && col <= ec)
  912.             attr = block;
  913.          if (col < len)
  914.             c = *text++;
  915.          else if (col == len && show_eol)
  916.             c = EOL_CHAR;
  917.          else
  918.             c = ' ';
  919.          *screen_ptr++ = c;
  920.          *screen_ptr++ = attr;
  921.  
  922.          c_output( c, bcol, line, attr );
  923.       }
  924. */
  925.    } else if (block_line == TRUE && file->block_type == STREAM &&
  926.               (rline == file->block_br || rline == file->block_er)) {
  927.       if (rline == file->block_br)
  928.          bc = file->block_bc;
  929.       else {
  930.          bc = file->block_ec + 1;
  931.          ec = normal;
  932.          normal = block;
  933.          block = ec;
  934.       }
  935.       if (bc < bcol)
  936.          bc = 0;
  937.       else if (bc < bcol + max_col)
  938.          bc = bc - bcol;
  939.       else
  940.          bc = max_col + 1;
  941.  
  942.  
  943.    ASSEMBLE {
  944.         /*
  945.         ; Register strategy:
  946.         ;   bl == beginning column
  947.         ;   bh == relative line length
  948.         ;   dl == normal text attribute
  949.         ;   dh == block attribute
  950.         ;   cl == current virtual column
  951.         ;   ch == maximum columns in window
  952.         ;   ES:DI == screen pointer (destination)
  953.         ;   DS:SI == text pointer (source)
  954.         ;   [bp+show_eol]  == access for local C variable
  955.         */
  956.  
  957.         push    ds                      /* MUST save ds - push it on stack */
  958.         push    si                      /* save si on stack */
  959.         push    di                      /* save di on stack */
  960.  
  961. /*
  962. ;
  963. ; set up local register variables
  964. ;
  965. */
  966.         mov     ax, WORD PTR bc         /* get beginning column */
  967.         mov     bl, al                  /* keep it in bl */
  968.         mov     ax, WORD PTR len        /* get relative line length */
  969.         mov     bh, al                  /* keep it in bh */
  970.         mov     ax, WORD PTR normal     /* get normal attribute */
  971.         mov     dl, al                  /* keep it in dl */
  972.         mov     ax, WORD PTR block      /* get block attribute */
  973.         mov     dh, al                  /* keep it in dh */
  974.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  975.         mov     ch, al                  /* keep it in ch */
  976.         xor     cl, cl                  /* col = 0, keep col in cl */
  977. /*
  978. ;
  979. ; load screen and text pointer
  980. ;
  981. */
  982.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  983.         add     di, WORD PTR off                /* add offset of line */
  984.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  985.         mov     es, ax
  986.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  987.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  988.         mov     ds, ax                  /* move segment of text in ds */
  989.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  990.         jne     nott_null               /* no, output string */
  991.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  992.         je      ddspl_eol               /* yes, clear end of line */
  993.    }
  994. nott_null:
  995.  
  996.    ASSEMBLE {
  997.         cmp     cl, ch          /* is col == max_col? */
  998.         je      ggetout         /* yes, thru with line */
  999.         cmp     cl, bh          /* is col == len? */
  1000.         je      ddspl_eol       /* yes, check eol display */
  1001.    }
  1002. ttop:
  1003.  
  1004.    ASSEMBLE {
  1005.         lodsb                   /* get next char in string */
  1006.         mov     ah, dl          /* assume normal attribute */
  1007.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1008.         jl      str_out1        /* yes, show char and normal attribute */
  1009.         mov     ah, dh          /* must be in a block - show block attribute */
  1010.    }
  1011. str_out1:
  1012.  
  1013.    ASSEMBLE {
  1014.         stosw                   /* else show char on screen */
  1015.         inc     cl              /* ++col */
  1016.         cmp     cl, ch          /* is col == max_col? */
  1017.         je      ggetout         /* yes, thru with line */
  1018.         cmp     cl, bh          /* is col == len? */
  1019.         jl      ttop            /* yes, check eol display */
  1020.    }
  1021. ddspl_eol:
  1022.  
  1023.    ASSEMBLE {
  1024.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1025.         je      stream_eol      /* show_eol flag is FALSE, blank line */
  1026.         mov     al, EOL_CHAR    /* load some eol indicator */
  1027.         mov     ah, dl          /* assume normal attribute */
  1028.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1029.         jl      str_out2        /* yes, show char and normal attribute */
  1030.         mov     ah, dh          /* must be in a block - show block attribute */
  1031.    }
  1032. str_out2:
  1033.  
  1034.    ASSEMBLE {
  1035.         stosw                   /* write blank and attribute to screen */
  1036.         inc     cl              /* ++col */
  1037.         cmp     cl, ch          /* is col == max_col? */
  1038.         jge     ggetout         /* yes, we're done */
  1039.    }
  1040. stream_eol:
  1041.  
  1042.    ASSEMBLE {
  1043.         mov     al, ' '         /* clear rest of line w/ spaces */
  1044.    }
  1045. c1:
  1046.  
  1047.    ASSEMBLE {
  1048.         mov     ah, dl          /* assume normal attribute */
  1049.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1050.         jl      str_out3        /* yes, show char and normal attribute */
  1051.         mov     ah, dh          /* must be in a block - show block attribute */
  1052.    }
  1053. str_out3:
  1054.  
  1055.    ASSEMBLE {
  1056.         stosw                   /* write blank and attribute to screen */
  1057.         inc     cl              /* ++col */
  1058.         cmp     cl, ch          /* is col == max_col? */
  1059.         jl      c1              /* while less output block */
  1060.    }
  1061. ggetout:
  1062.  
  1063.    ASSEMBLE {
  1064.         pop     di
  1065.         pop     si
  1066.         pop     ds
  1067.       }
  1068.  
  1069. /*
  1070.       screen_ptr += off;
  1071.       bcol = window->start_col;
  1072.       for (col=0; col < max_col; col++, bcol++) {
  1073.          attr = normal;
  1074.          if (col >= bc && col <= ec)
  1075.             attr = block;
  1076.          if (col < len)
  1077.             c = *text++;
  1078.          else if (col == len && show_eol)
  1079.             c = EOL_CHAR;
  1080.          else
  1081.             c = ' ';
  1082.          *screen_ptr++ = c;
  1083.          *screen_ptr++ = attr;
  1084.          c_output( c, bcol, line, attr );
  1085.       }
  1086. */
  1087.    } else {
  1088.       if (block_line)
  1089.          attr = block;
  1090.       else
  1091.          attr = normal;
  1092.  
  1093.       assert( len >= 0 );
  1094.       assert( len <= MAX_COLS );
  1095.  
  1096.    ASSEMBLE {
  1097.         /*
  1098.         ; Register strategy:
  1099.         ;   bl == normal text attribute
  1100.         ;   bh == relative line length
  1101.         ;   cl == current virtual column
  1102.         ;   ch == maximum columns in window
  1103.         ;   ES:DI == screen pointer (destination)
  1104.         ;   DS:SI == text pointer (source)
  1105.         ;   [bp+show_eol]  == access for local C variable
  1106.         */
  1107.  
  1108.         mov     dx, ds          /* MUST save ds - keep it in dx */
  1109.         push    di              /* save di on stack */
  1110.         push    si              /* save si on stack */
  1111.  
  1112.  
  1113.         mov     bx, WORD PTR attr               /* keep attribute in bl */
  1114.         mov     ax, WORD PTR len                /* get normalized len */
  1115.         mov     bh, al                          /* keep len in bh */
  1116.         mov     cx, WORD PTR max_col            /* get max_col in cx */
  1117.         mov     ch, cl                          /* keep it in ch */
  1118.         xor     cl, cl                          /* zero out cl */
  1119.         mov     di, WORD PTR screen_ptr         /* load OFFST of screen ptr */
  1120.         add     di, WORD PTR off                /* add offset of line */
  1121.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1122.         mov     es, ax
  1123.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1124.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1125.         mov     ds, ax                  /* move segment of text in ds */
  1126.         cmp     si, 0                   /* is offset of pointer == NULL? */
  1127.         jne     nnot_null               /* no, output string */
  1128.         cmp     ax, 0                   /* is segment of pointer == NULL? */
  1129.         je      normeol                 /* yes, then clear rest of line */
  1130.    }
  1131. nnot_null:
  1132.  
  1133.    ASSEMBLE {
  1134.         mov     ah, bl                  /* get attribute */
  1135.         cmp     cl, ch          /* compare count with max columns */
  1136.         jge     getoutt         /* yes, thru with line */
  1137.         cmp     cl, bh          /* compare count with len */
  1138.         je      normeol         /* yes, clear end of line */
  1139.    }
  1140. topp:
  1141.  
  1142.    ASSEMBLE {
  1143.         lodsb                   /* get next char in string */
  1144.         stosw                   /* else show char on screen */
  1145.         inc     cl              /* ++col, count up to max_column */
  1146.         cmp     cl, ch          /* compare count with max columns */
  1147.         jge     getoutt         /* yes, thru with line */
  1148.         cmp     cl, bh          /* compare count with len */
  1149.         jl      topp            /* yes, clear end of line */
  1150.    }
  1151. normeol:
  1152.  
  1153.    ASSEMBLE {
  1154.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1155.         je      clreol          /* show_eol flag is FALSE, blank line */
  1156.         mov     al, EOL_CHAR    /* load some eol indicator */
  1157.         mov     ah, bl          /* assume normal attribute */
  1158.         stosw                   /* write blank and attribute to screen */
  1159.         inc     cl              /* ++col */
  1160.         cmp     cl, ch          /* is col == max_col? */
  1161.         jge     getoutt         /* yes, we're done */
  1162.    }
  1163. clreol:
  1164.  
  1165.    ASSEMBLE {
  1166.         mov     ah, bl          /* get attribute */
  1167.         mov     al, ' '         /* clear eol with ' ' */
  1168.         sub     ch, cl          /* find number of columns left */
  1169.         mov     cl, ch          /* put number of column left in cl */
  1170.         xor     ch, ch          /* clear ch */
  1171.         rep     stosw           /* count is in cx - set rest of line to ' ' */
  1172.    }
  1173. getoutt:
  1174.  
  1175.    ASSEMBLE {
  1176.         pop     si
  1177.         pop     di
  1178.         mov     ds, dx
  1179.       }
  1180.  
  1181. /*
  1182.       screen_ptr += off;
  1183.       bcol = window->start_col;
  1184.       for (col=0; col < max_col; col++, bcol++) {
  1185.          attr = normal;
  1186.          if (col < len)
  1187.             c = *text++;
  1188.          else if (col == len && show_eol)
  1189.             c = EOL_CHAR;
  1190.          else
  1191.             c = ' ';
  1192.          *screen_ptr++ = c;
  1193.          *screen_ptr++ = attr;
  1194.          c_output( c, bcol, line, attr );
  1195.       }
  1196. */
  1197.    }
  1198. }
  1199.  
  1200.  
  1201. /*
  1202.  * Name:    c_output
  1203.  * Purpose: Output one character on prompt lines
  1204.  * Date:    June 5, 1991
  1205.  * Passed:  c:     character to output to screen
  1206.  *          col:   col to display character
  1207.  *          line:  line number to display character
  1208.  *          attr:  attribute of character
  1209.  * Returns: none
  1210.  */
  1211. void c_output( int c, int col, int line, int attr )
  1212. {
  1213. void far *screen_ptr;
  1214. int  off;
  1215.  
  1216.    screen_ptr = (void far *)g_display.display_address;
  1217.    off = line * 160 + col * 2;
  1218.  
  1219.    ASSEMBLE {
  1220.         mov     bx, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1221.         add     bx, WORD PTR off                /* add offset of line:col */
  1222.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1223.         mov     es, ax
  1224.         mov     cx, WORD PTR attr       /* get attribute */
  1225.         mov     ah, cl                  /* put in ah */
  1226.         mov     cx, WORD PTR c          /* get character */
  1227.         mov     al, cl                  /* put in al */
  1228.         mov     WORD PTR es:[bx], ax    /* show char on screen */
  1229.    }
  1230.  
  1231. /*
  1232.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1233.    *screen_ptr++ = c;
  1234.    *screen_ptr = attr;
  1235. */
  1236. }
  1237.  
  1238.  
  1239. /*
  1240.  * Name:    s_output
  1241.  * Purpose: To output a string
  1242.  * Date:    June 5, 1991
  1243.  * Passed:  s:     string to output
  1244.  *          line:  line to display
  1245.  *          col:   column to begin display
  1246.  *          attr:  color to display string
  1247.  * Notes:   This function is used to output most strings not part of file text.
  1248.  */
  1249. void s_output( char far *s, int line, int col, int attr )
  1250. {
  1251. void far *screen_ptr;
  1252. int  off;
  1253. int  max_col;
  1254.  
  1255.    max_col = g_display.ncols;
  1256.    screen_ptr = (void far *)g_display.display_address;
  1257.    off = line * 160 + col * 2;
  1258.  
  1259.    ASSEMBLE {
  1260.         push    ds              /* save ds on stack */
  1261.         push    di              /* save di on stack */
  1262.         push    si              /* save si on stack */
  1263.  
  1264.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1265.         mov     cx, WORD PTR col                /* put cols in cx */
  1266.         mov     dx, WORD PTR max_col            /* keep max_col in dx */
  1267.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1268.         add     di, WORD PTR off                /* add offset of line:col */
  1269.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1270.         mov     es, ax
  1271.         mov     si, WORD PTR s  /* load offset of string ptr */
  1272.         or      si, si          /* is it == NULL? */
  1273.         je      getout          /* yes, no output needed */
  1274.         mov     ax, WORD PTR s+2        /* load segment of string ptr */
  1275.         or      ax, ax          /* is pointer == NULL? */
  1276.         je      getout          /* yes, no output needed */
  1277.         mov     ds, ax          /* load segment of text in ds */
  1278.         mov     ah, bl          /* put attribute in AH */
  1279.    }
  1280. top:
  1281.  
  1282.    ASSEMBLE {
  1283.         cmp     cx, dx          /* col < max_cols? */
  1284.         jge     getout          /* no, thru with line */
  1285.         lodsb                   /* get next char in string - put in al */
  1286.         or      al, al          /* is it '\0' */
  1287.         je      getout          /* yes, end of string */
  1288.         cmp     al, 0x0a        /* is it '\n'? */
  1289.         je      getout          /* yes, end of string */
  1290.         stosw                   /* else show attr + char on screen (ah + al) */
  1291.         inc     cx              /* col++ */
  1292.         jmp     SHORT top       /* get another character */
  1293.    }
  1294. getout:
  1295.  
  1296.    ASSEMBLE {
  1297.         pop     si              /* get back si */
  1298.         pop     di              /* get back di */
  1299.         pop     ds              /* get back ds */
  1300.    }
  1301.  
  1302. /*
  1303.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1304.    max_col = g_display.ncols;
  1305.    while (*s && col < max) {
  1306.       *screen_ptr++ = *s++;
  1307.       *screen_ptr++ = attr;
  1308.    }
  1309. */
  1310. }
  1311.  
  1312.  
  1313. /*
  1314.  * Name:    eol_clear
  1315.  * Purpose: To clear the line from col to max columns
  1316.  * Date:    June 5, 1991
  1317.  * Passed:  col:   column to begin clear
  1318.  *          line:  line to clear
  1319.  *          attr:  color to clear
  1320.  * Notes:   Basic assembly
  1321.  */
  1322. void eol_clear( int col, int line, int attr )
  1323. {
  1324. int  max_col;
  1325. void far *screen_ptr;
  1326. int  off;
  1327.  
  1328.    max_col = g_display.ncols;
  1329.    screen_ptr = (void far *)g_display.display_address;
  1330.    off = line * 160 + col * 2;
  1331.  
  1332.    ASSEMBLE {
  1333.         push    di                              /* save di on stack */
  1334.  
  1335.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1336.         mov     dx, WORD PTR col                /* put cols in dx */
  1337.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1338.         cmp     dx, cx                          /* max_cols < cols? */
  1339.         jge     getout                          /* no, thru with line */
  1340.         sub     cx, dx                          /* number of column to clear */
  1341.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1342.         add     di, WORD PTR off                /* add offset of line:col */
  1343.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1344.         mov     es, ax
  1345.         mov     ah, bl                          /* get attribute in ah */
  1346.         mov     al, ' '                         /* store ' ' in al */
  1347.         rep     stosw                           /* clear to end of line */
  1348.    }
  1349. getout:
  1350.  
  1351.    ASSEMBLE {
  1352.         pop     di                              /* get back di from stack */
  1353.    }
  1354.  
  1355. /*
  1356.    for (; col < g_display.ncols; col++) {
  1357.       *p++ = ' ';
  1358.       *p++ = attr;
  1359.    }
  1360. */
  1361. }
  1362.  
  1363.  
  1364. /*
  1365.  * Name:    window_eol_clear
  1366.  * Purpose: To clear the line from start_col to end_col
  1367.  * Date:    June 5, 1991
  1368.  * Passed:  col:   column to begin clear
  1369.  *          line:  line to clear
  1370.  *          attr:  color to clear
  1371.  * Notes:   Basic assembly
  1372.  */
  1373. void window_eol_clear( WINDOW *window, int attr )
  1374. {
  1375. int  max_col;
  1376. void far *screen_ptr;
  1377. int  off;
  1378.  
  1379.    if (!g_status.screen_display)
  1380.       return;
  1381.    screen_ptr = (void far *)g_display.display_address;
  1382.    off = window->cline * 160 + window->start_col * 2;
  1383.    max_col = window->end_col + 1 - window->start_col;
  1384.  
  1385.    ASSEMBLE {
  1386.         push    di                              /* save di on stack */
  1387.  
  1388.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1389.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1390.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1391.         add     di, WORD PTR off                /* add offset of line:col */
  1392.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1393.         mov     es, ax
  1394.         mov     ah, bl                          /* get attribute in ah */
  1395.         mov     al, ' '                         /* store ' ' in al */
  1396.         rep     stosw                           /* clear to end of line */
  1397.  
  1398.         pop     di                              /* get back di from stack */
  1399.    }
  1400.  
  1401. /*
  1402.    for (; col < g_display.ncols; col++) {
  1403.       *p++ = ' ';
  1404.       *p++ = attr;
  1405.    }
  1406. */
  1407. }
  1408.  
  1409.  
  1410. /*
  1411.  * Name:    hlight_line
  1412.  * Date:    July 21, 1991
  1413.  * Passed:  x:     column to begin hi lite
  1414.  *          y:     line to begin hi lite
  1415.  *          lgth:  number of characters to hi lite
  1416.  *          attr:  attribute color
  1417.  * Notes:   The attribute byte is the hi byte.
  1418.  */
  1419. void hlight_line( int x, int y, int lgth, int attr )
  1420. {
  1421. int  off;
  1422. void far *screen_ptr;
  1423.  
  1424.    screen_ptr = (void far *)g_display.display_address;
  1425.    off = y * 160 + 2 * x + 1;  /* add one - so it points to attribute byte */
  1426.  
  1427.    ASSEMBLE {
  1428.         push    di              /* save di */
  1429.  
  1430.         mov     cx, lgth        /* number of characters to change color */
  1431.  
  1432.         mov     di, WORD PTR screen_ptr /* get destination - video memory */
  1433.         add     di, off                 /* add offset */
  1434.         mov     ax, WORD PTR screen_ptr+2
  1435.         mov     es, ax
  1436.         mov     ax, attr        /* attribute */
  1437.    }
  1438. lite_len:
  1439.  
  1440.    ASSEMBLE {
  1441.         stosb                   /* store a BYTE */
  1442.         inc     di              /* skip over character to next attribute */
  1443.         loop    lite_len        /* change next attribute */
  1444.         pop     di              /* restore di */
  1445.    }
  1446. }
  1447.  
  1448.  
  1449. /*
  1450.  * Name:    cls
  1451.  * Purpose: clear screen
  1452.  * Date:    June 5, 1991
  1453.  * Notes:   Call the video BIOS routine to clear the screen.
  1454.  */
  1455. void cls( void )
  1456. {
  1457. int  line;
  1458.  
  1459.      line = g_display.nlines + 1;
  1460.  
  1461.    ASSEMBLE {
  1462.         xor     ch, ch                  /* starting row in ch = 0 */
  1463.         xor     cl, cl                  /* starting column in cl = 0 */
  1464.         mov     ax, WORD PTR line       /* get ending row */
  1465.         mov     dh, al                  /* put it in dh */
  1466.         mov     dl, 79                  /* ending column in dl = 79 */
  1467.         mov     bh, 7                   /* attribute in bh  = 7 (normal) */
  1468.         mov     al, 0                   /* get number of lines */
  1469.         mov     ah, 6                   /* get function number */
  1470.         push    bp                      /* some BIOS versions wipe out bp */
  1471.         int     0x10
  1472.         pop     bp
  1473.    }
  1474. }
  1475.  
  1476.  
  1477. /*
  1478.  * Name:    set_cursor_size
  1479.  * Purpose: To set cursor size according to insert mode.
  1480.  * Date:    June 5, 1991
  1481.  * Passed:  csize:  desired cursor size
  1482.  * Notes:   use the global display structures to set the cursor size
  1483.  */
  1484. void set_cursor_size( int csize )
  1485. {
  1486.    ASSEMBLE {
  1487.         mov     ah, 1                   /* function 1 - set cursor size */
  1488.         mov     cx, WORD PTR csize      /* get cursor size ch:cl == top:bot */
  1489.         push    bp
  1490.         int     VIDEO_INT               /* video interrupt = 10h */
  1491.         pop     bp
  1492.    }
  1493. }
  1494.  
  1495.  
  1496. /*
  1497.  * Name:    set_overscan_color
  1498.  * Purpose: To set overscan color
  1499.  * Date:    April 1, 1993
  1500.  * Passed:  color:  overscan color
  1501.  * Notes:   before setting the overscan color, the old overscan color
  1502.  *           needs to be saved so it can be restored.
  1503.  */
  1504. void set_overscan_color( int color )
  1505. {
  1506.    ASSEMBLE {
  1507.         mov     ah, 0x0b                /* function 0x0b */
  1508.         mov     bl, BYTE PTR color      /* get new overscan color */
  1509.         xor     bh, bh
  1510.         push    bp
  1511.         int     VIDEO_INT               /* video interrupt = 10h */
  1512.         pop     bp
  1513.    }
  1514. }
  1515.  
  1516.  
  1517. /*
  1518.  * Name:    save_screen_line
  1519.  * Purpose: To save the characters and attributes of a line on screen.
  1520.  * Date:    June 5, 1991
  1521.  * Passed:  col:    desired column, usually always zero
  1522.  *          line:   line on screen to save (0 up to max)
  1523.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  1524.  * Notes:   Save the contents of the line on screen where prompt is
  1525.  *           to be displayed
  1526.  */
  1527. void save_screen_line( int col, int line, char *screen_buffer )
  1528. {
  1529. char far *p;
  1530.  
  1531.    p = g_display.display_address + line * 160 + col * 2;
  1532.    _fmemcpy( screen_buffer, p, 160 );
  1533. }
  1534.  
  1535.  
  1536. /*
  1537.  * Name:    restore_screen_line
  1538.  * Purpose: To restore the characters and attributes of a line on screen.
  1539.  * Date:    June 5, 1991
  1540.  * Passed:  col:    usually always zero
  1541.  *          line:   line to restore (0 up to max)
  1542.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  1543.  * Notes:   Restore the contents of the line on screen where the prompt
  1544.  *           was displayed
  1545.  */
  1546. void restore_screen_line( int col, int line, char *screen_buffer )
  1547. {
  1548. char far *p;
  1549.  
  1550.    p = g_display.display_address + line * 160 + col * 2;
  1551.    _fmemcpy( p, screen_buffer, 160 );
  1552. }
  1553.